#include "Model.h"

Model::Model(QObject *parent)
    : QObject(parent)
{
}

QString Model::OpenLoadSffFileDlg()
{
    QString filePath = getFilePathByFileDlg("打开Sff", "sff");
    if (filePath.isEmpty()) {
        qDebug() << Q_FUNC_INFO << "not select sff file path";
        return "";
    }

    LoadSff(filePath);
    return filePath;
}

QString Model::OpenLoadAirFileDlg()
{
    QString filePath = getFilePathByFileDlg("打开Air", "air");
    if (filePath.isEmpty()) {
        qDebug() << Q_FUNC_INFO << "not select air file path";
        return "";
    }

    LoadAir(filePath);
    return filePath;
}

void Model::LoadSff(const QString &path)
{
    m_sff = Sff();
    LoadMugenSffFile(path.toUtf8().data(), &m_sff);
    m_mapOfIdToSpriteGroup.clear();
    QMap<int, SpriteGroup> mapOfIdToSpirteGroup;
    int spriteIdx = 0;
    for (const Sprite &s : m_sff.Sprites) {
        SpriteGroup &g = mapOfIdToSpirteGroup[s.Group];
        g.MapOfGroupSpriteNumToRealSpriteIdx.insert(s.Number, spriteIdx);
        spriteIdx++;
    }

    // Sprite Group
    for (const int &id : mapOfIdToSpirteGroup.keys()) {
        SpriteGroup &g = mapOfIdToSpirteGroup[id];
        g.Id = id;
        m_mapOfIdToSpriteGroup.insert(id, g);
    }
}

void Model::LoadAir(const QString &path)
{
    m_actionList.clear();
    m_airManager.DecAir(path.toUtf8().data());
    const std::vector<Action> &vector = m_airManager.GetActionVector();
    for (const Action &a : vector) {
        m_actionList.append(a);
    }

    Q_EMIT LoadAirFinished();
}

void Model::OpenExportFileDlg()
{
    QString dirPath = getDirPathByFileDlg();
    if (dirPath.isEmpty()) {
        qDebug() << Q_FUNC_INFO << "not select exporting dir path";
        return;
    }

    Export(dirPath);
}

void Model::Export(const QString &outputDirPath)
{
    const QString &fileName = QFileInfo(m_sff.Filename).fileName();
    const QString &imgOutputDirPath = QString("%1/Img/%2")
                                            .arg(outputDirPath)
                                            .arg(fileName);
    QDir dir(imgOutputDirPath);
    if (!dir.exists()) {
        dir.mkpath(dir.absolutePath());
    }

    const QString &spriteInfoOutputDirPath = QString("%1/Sprite/%2")
                                               .arg(outputDirPath)
                                               .arg(fileName);
    dir.setPath(spriteInfoOutputDirPath);
    if (!dir.exists()) {
        dir.mkpath(dir.absolutePath());
    }
    // frame ani dir
    const QString &frameAniOutputDirPath = QString("%1/FrameAni/%2")
                                               .arg(outputDirPath)
                                               .arg(fileName);
    dir.setPath(frameAniOutputDirPath);
    if (!dir.exists()) {
        dir.mkpath(dir.absolutePath());
    }

    for (uint i = 0; i < m_sff.Sprites.size(); i++) {
        const Sprite &sprite = m_sff.Sprites[i];
        // output img
        const QString &imgFileOutputPath = QString("%1/%2.png")
                                               .arg(imgOutputDirPath)
                                               .arg(i);
        const QImage &img = GetSpriteImg(sprite);
        img.save(imgFileOutputPath, "png");

        // output sprite info lua
        const QString &spriteInfoOutputFilePath = QString("%1/%2.cfg")
                                               .arg(spriteInfoOutputDirPath)
                                               .arg(i);
        QFile f(spriteInfoOutputFilePath);
        if (!f.open(QIODevice::OpenModeFlag::WriteOnly)) {
            qCritical() << Q_FUNC_INFO << spriteInfoOutputFilePath << "open failed!";
            continue;
        }

        const QString &luaContentStr = QString("return {\n    ox = %1,\n    oy = %2\n}")
                                        .arg(sprite.OX).arg(sprite.OY);
        f.write(luaContentStr.toUtf8());
        f.close();
    }

    // frame ani
    const QList<Action> &list = m_actionList;
    for (const Action &a : list) {
        QString aniName = QString("（%1）%2").arg(a.Id).arg(QString::fromStdString(a.Name));
        // write lua
        QString frameAniOutputFilePath = QString("%1/%2.cfg")
                .arg(frameAniOutputDirPath)
                .arg(aniName);
        QFile f(frameAniOutputFilePath);
        if (!f.open(QIODevice::OpenModeFlag::WriteOnly)) {
            qCritical() << Q_FUNC_INFO << frameAniOutputFilePath << "open failed!";
            continue;
        }

        QString luaContentStr = QString("return {\n");
        for (uint i = 0; i < a.Ani.Size(); i++) {
            const SFrame &frame = a.Ani[i];
            if (!m_mapOfIdToSpriteGroup.contains(frame.Group)) {
                qCritical() << Q_FUNC_INFO << "not has sprite group:" << frame.Group;
                continue;
            }
            const SpriteGroup &group = m_mapOfIdToSpriteGroup.value(frame.Group);
            int spriteIdx = group.MapOfGroupSpriteNumToRealSpriteIdx.value(frame.Image);

            QString frameUnitStr = QString("    {\n"
                                           "        sprite = \"%1\",\n"
                                           "        time = %2\n"
                                           "    },\n").arg(spriteIdx).arg(frame.Delay * 20);
            luaContentStr += frameUnitStr;

        }
        luaContentStr += "}";
        f.write(luaContentStr.toUtf8());
        f.close();
    }
}

const QList<Action> &Model::GetActionList()
{
    return m_actionList;
}

QList<Sprite> Model::GetSpriteListByAction(const Action &a)
{
    QList<Sprite> list;
    for (uint i = 0; i < a.Ani.Size(); i++) {
        const SFrame &frame = a.Ani[i];
        if (!m_mapOfIdToSpriteGroup.contains(frame.Group)) {
            qCritical() << Q_FUNC_INFO << "not has sprite group:" << frame.Group;
            continue;
        }
        const SpriteGroup &group = m_mapOfIdToSpriteGroup.value(frame.Group);
        int spriteIdx = group.MapOfGroupSpriteNumToRealSpriteIdx.value(frame.Image);
        const Sprite &s = m_sff.Sprites.at(spriteIdx);
        list.append(s);
    }

    return list;
}

QImage Model::GetSpriteImg(const Sprite &sprite)
{
    int w = sprite.W;
    int h = sprite.H;
    QImage img(w, h, QImage::Format_ARGB32);
    for (int y = 0; y < h; y++) {
        for (int x = 0; x < w; x++) {
            Color color = sprite.ColorList.at(y * w + x);
            QColor c(color.R, color.G, color.B, color.A);
            img.setPixelColor(x, y, c);
        }
    }

    return img;
}

QString Model::getFilePathByFileDlg(const QString &title, const QString &suffix)
{
    const QString &localDataDirPath = QStandardPaths::writableLocation(QStandardPaths::StandardLocation::DesktopLocation);

    QString defaultFilePath = QString("%1/").arg(localDataDirPath);

    QFileInfo fInfo(defaultFilePath);
    QDir dir = fInfo.dir();
    if (!dir.exists()) {
        dir.mkpath(dir.absolutePath());
    }

    QString filePath = QFileDialog::getOpenFileName(nullptr, title, defaultFilePath, "*." + suffix);
    return filePath;
}

QString Model::getDirPathByFileDlg()
{
    const QString &localDataDirPath = QStandardPaths::writableLocation(QStandardPaths::StandardLocation::DesktopLocation);

    QString defaultDirPath = QString("%1/MugenResOutput/").arg(localDataDirPath);

    QFileInfo fInfo(defaultDirPath);
    QDir dir = fInfo.dir();
    if (!dir.exists()) {
        dir.mkpath(dir.absolutePath());
    }

    QString dirPath = QFileDialog::getExistingDirectory(nullptr, "导出", defaultDirPath);
    return dirPath;
}
